home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / v7n20.arc / CONFIG.ASM < prev    next >
Assembly Source File  |  1988-10-29  |  37KB  |  822 lines

  1. ;----------------------------------------------------------------;
  2. ;  CONFIG.CTL - Allows you to dynamically change your CONFIG.SYS ;
  3. ;  configuration at boot time.  Add DEVICE = CONFIG.CTL [m]      ;
  4. ;  to your CONFIG.SYS just ahead of the first command you wish   ;
  5. ;  to be able to modify.  m is seconds CONFIG.CTL will pause     ;
  6. ;  for a keystroke before booting normally.  m defaults to zero. ;
  7. ;  Add DEVICE = CONFIG.END after the last command you wish to be ;
  8. ;  able to modify.  CONFIG.END is a dummy device and must appear ;
  9. ;  in CONFIG.SYS in order for CONFIG.CTL to operate.             ;
  10. ;  Requires MASM 2.0 or later. Remember to EXE2BIN               ;
  11. ;  CONFIG.CTL 1.0 (C) 1988 Ziff Communications Co.
  12. ;----------------------------------------------------------------;
  13. _TEXT          SEGMENT PUBLIC 'CODE'
  14.                ASSUME  CS:_TEXT,DS:_TEXT
  15.                ASSUME  ES:_TEXT,SS:_TEXT
  16.                ORG     0H
  17.  
  18. ;************* DEVICE_HEADER *************;
  19. POINTER        DD      -1
  20. ATTRIBUTE      DW      1000000000000000B
  21. DEVICE_STAG    DW      STRATEGY
  22. DEVICE_INT     DW      INTERRUPT
  23. DEVICE_NAME    DB      "CONFIGURE"
  24.  
  25. CR             EQU     13
  26. LF             EQU     10
  27. CTRL_Z         EQU     26
  28. SPACE          EQU     32
  29. COMMA          EQU     44
  30. FORWARD_SLASH  EQU     47
  31. BOX            EQU     254
  32. ;-------------------------;
  33. REQUEST_HEADER STRUC
  34.  
  35. HEADER_LENGTH  DB      ?
  36. UNIT_CODE      DB      ?
  37. COMMAND_CODE   DB      ?
  38. STATUS         DW      ?
  39. RESERVED       DQ      ?
  40.  
  41. REQUEST_HEADER ENDS
  42.  
  43. DONE           EQU     0000000100000000B       ;Status codes.
  44. UNKNOWN        EQU     1000000000000011B
  45. ;-------------------------;
  46. INIT           STRUC
  47.  
  48. HEADER         DB      (TYPE REQUEST_HEADER) DUP(?)
  49. UNITS          DB      ?
  50. ENDING_OFFSET  DW      ?
  51. ENDING_SEGMENT DW      ?
  52. ARGUMENTS_OFF  DW      ?
  53. ARGUMENTS_SEG  DW      ?
  54.  
  55. INIT           ENDS
  56.  
  57. REQUEST_OFFSET DW      ?
  58. REQUEST_SEG    DW      ?
  59.  
  60. ;-----------------------------------------------------------------------------;
  61. ; The only task of the strategy is to save the pointer to the request header. ;
  62. ;-----------------------------------------------------------------------------;
  63. STRATEGY       PROC    FAR
  64.  
  65.                MOV     CS:REQUEST_OFFSET,BX    ;Request header address is
  66.                MOV     CS:REQUEST_SEG,ES       ; passed in ES:BX.
  67.                RET
  68.  
  69. STRATEGY       ENDP
  70.  
  71. ;------------------------------------------------------------------------;
  72. ; The interrupt procedure will be called immediately after the strategy. ;
  73. ;------------------------------------------------------------------------;
  74. INTERRUPT      PROC    FAR
  75.  
  76.                PUSH    AX                      ;Responsible for all registers.
  77.                PUSH    BX
  78.                PUSH    CX
  79.                PUSH    DX
  80.                PUSH    DS
  81.                PUSHF
  82.  
  83.                MOV     DS,CS:REQUEST_SEG       ;Retrieve request header pointer.
  84.                MOV     BX,CS:REQUEST_OFFSET
  85.  
  86.                OR      STATUS[BX],DONE         ;Tell DOS we are done.
  87.                CMP     COMMAND_CODE[BX],0      ;Is it INIT command?
  88.                JZ      MAKE_STACK              ;If yes, do our stuff.
  89.                OR      STATUS[BX],UNKNOWN      ;Else, exit with confused
  90.                JMP     SHORT UNKNOWN_EXIT      ; message to DOS.
  91.  
  92. MAKE_STACK:    MOV     CX,SS                   ;Save DOS stack.
  93.                MOV     DX,SP
  94.                MOV     AX,CS
  95.                CLI
  96.                MOV     SS,AX                   ;Make new stack.
  97.                MOV     SP,0FFFEH
  98.                STI
  99.                PUSH    CX                      ;Save old stack pointers on new.
  100.                PUSH    DX
  101.  
  102.                PUSH    ES                      ;Save rest of registers.
  103.                PUSH    SI
  104.                PUSH    DI
  105.                PUSH    BP
  106.  
  107.                CALL    INITIALIZE              ;Go do our stuff.
  108.  
  109.                POP     BP                      ;Restore registers.
  110.                POP     DI
  111.                POP     SI
  112.                POP     ES
  113.  
  114.                POP     DX                      ;Restore old DOS stack.
  115.                POP     CX
  116.                CLI
  117.                MOV     SS,CX
  118.                MOV     SP,DX
  119.                STI
  120.  
  121. UNKNOWN_EXIT:  POPF                            ;Restore rest of registers.
  122.                POP     DS
  123.                POP     DX
  124.                POP     CX
  125.                POP     BX
  126.                POP     AX
  127.                RET                             ;Far return back to DOS.
  128.  
  129. INTERRUPT      ENDP
  130.  
  131. CONFIG_CTL_END LABEL   WORD
  132.  
  133. ;************* END OF RESIDENT PORTION *************;
  134.  
  135. BUFFER_SEGMENT DW      ?                       ;CONFIG.SYS buffer segment
  136. BUFFER_START   DW      ?                       ; and offset.
  137. BUFFER_END     DW      ?                       ;CONFIG.END address.
  138. END_FLAG       DB      0                       ;CONFIG.END found flag.
  139.  
  140. CONFIG_END     DB      "DCONFIG.END"
  141. CONFIG_END_LEN EQU     $ - CONFIG_END
  142.  
  143. DELAY_MSG      DB      CR,LF,LF,"Press any key if you wish to modify the "
  144.                DB      "CONFIG.SYS configuration.",CR,LF
  145.                DB      "Press Esc for quick bypass of CONFIG.CTL.",CR,LF,LF,"$"
  146. NOT_FOUND_MSG  DB      "DEVICE=CONFIG.END has to be added as a terminating "
  147.                DB      CR,LF,"command in CONFIG.SYS before CONFIG.CTL can "
  148.                DB      "function.",CR,LF,"Press and key to continue.$"
  149. ;--------------------------;
  150. NORMAL         EQU     07H                     ;Screen attributes.
  151. INVERSE        EQU     70H
  152.  
  153. HEADING        LABEL   BYTE
  154. DB "CONFIG.CTL 1.0 (C) 1988 Ziff Communications Co.",CR,LF
  155. DB "PC Magazine ",BOX," Michael J. Mefford",CR,LF,LF
  156.  
  157. DB "Press F1 to toggle active state of highlighted command.",CR,LF
  158. DB "You may optionally edit a highlighted command.",CR,LF
  159. DB "Press F2 to accept changes and exit.",CR,LF
  160. DB "Press Esc to abort changes and exit.",CR,LF
  161. DB "Note: Permanent changes are not made to the CONFIG.SYS file.$"
  162. ;----------------------------;
  163. STRING_MAX     EQU     80
  164. DISPLAY_MAX    EQU     67
  165. LAST_RECORD    EQU     -1
  166.  
  167. DATA_RECORD    STRUC
  168.  
  169. COMMAND        DB      STRING_MAX DUP (?)
  170. STRING_LENGTH  DW      ?
  171. ADDRESS        DW      ?                       ;Command string address start.
  172.  
  173. DATA_RECORD    ENDS
  174.  
  175. ROW_START      EQU     9
  176. COL_START      EQU     12
  177.  
  178. CODES          DB      "CBQDXFSKL"             ;DOS command codes.
  179. CODES_LENGTH   EQU     $ - CODES               ;For example "C" = BREAK
  180.  
  181. COMMAND_TABLE  DB      "BREAK"     ,5 DUP (SPACE), "BUFFERS" ,3 DUP (SPACE)
  182.                DB      "COUNTRY"   ,3 DUP (SPACE), "DEVICE"  ,4 DUP (SPACE)
  183.                DB      "FCBS"      ,6 DUP (SPACE), "FILES"   ,5 DUP (SPACE)
  184.                DB      "SHELL"     ,5 DUP (SPACE), "STACKS"  ,4 DUP (SPACE)
  185. LAST_COMMAND   DB      "LASTDRIVE" ,1 DUP (SPACE)
  186. TABLE_END      EQU     $
  187. COMMAND_SIZE   EQU     TABLE_END - LAST_COMMAND
  188.  
  189. INACTIVE       DB      "INACTIVE" ,2 DUP (SPACE)
  190.  
  191. HIGH_BIT       EQU     10000000B
  192. ESC_KEY        EQU     01H
  193. ENTER_KEY      EQU     1CH
  194. F1_KEY         EQU     3BH
  195. F2_KEY         EQU     3CH
  196. BACKSPACE_KEY  EQU     0EH
  197. UP_ARROW_KEY   EQU     48H
  198. DN_ARROW_KEY   EQU     50H
  199. LT_ARROW_KEY   EQU     4BH
  200. RT_ARROW_KEY   EQU     4DH
  201. HOME_KEY       EQU     47H
  202. END_KEY        EQU     4FH
  203. PG_UP_KEY      EQU     49H
  204. PG_DN_KEY      EQU     51H
  205. BS             EQU     8
  206.  
  207. DISPATCH_KEY   DB      F1_KEY, BACKSPACE_KEY, UP_ARROW_KEY, DN_ARROW_KEY
  208.                DB      LT_ARROW_KEY, RT_ARROW_KEY, HOME_KEY, END_KEY
  209.                DB      PG_UP_KEY, PG_DN_KEY, ENTER_KEY
  210. KEY_COUNT      EQU     $ - DISPATCH_KEY
  211.  
  212. DISPATCH_TABLE DW      F1, BACKSPACE, UP_ARROW, DN_ARROW
  213.                DW      LT_ARROW, RT_ARROW, HOME, END_CURSOR
  214.                DW      PG_UP, PG_DN, DN_ARROW
  215. DISPATCH_END   EQU     $ - 2
  216.  
  217. ;------------------------------------------;
  218. ; INPUT                                    ;
  219. ;   DS:BX points to request header.        ;
  220. ;                                          ;
  221. ;   All registers destroyed.               ;
  222. ;------------------------------------------;
  223. INITIALIZE     PROC    NEAR
  224.  
  225.                MOV     ENDING_OFFSET[BX],OFFSET CONFIG_CTL_END
  226.                MOV     ENDING_SEGMENT[BX],CS   ;Resident portion setup.
  227.  
  228.                MOV     AX,ARGUMENTS_SEG[BX]    ;Retrieve CONFIG.SYS buffer
  229.                MOV     ES,AX                   ; pointers from INIT table.
  230.                MOV     BX,ARGUMENTS_OFF[BX]
  231.                PUSH    CS                      ;Point to our data.
  232.                POP     DS
  233.                MOV     BUFFER_SEGMENT,ES       ;And save the segment.
  234.                CLD
  235. ;------------------------------------;
  236. ; Parse CONFIG.CTL second parameter. ;
  237. ;------------------------------------;
  238.                XOR     BP,BP                   ;Use BP to store seconds.
  239. NEXT_NUMBER:   MOV     AL,ES:[BX]              ;Retrieve a byte.
  240.                INC     BX                      ;Point to next byte.
  241.                CMP     AL,CR                   ;If carriage return of linefeed,
  242.                JZ      FIND_END                ; found end of parameter.
  243.                CMP     AL,LF
  244.                JZ      FIND_END
  245.                SUB     AL,"0"                  ;ASCII to binary.
  246.                JC      NEXT_NUMBER             ;If not between 0 and 9, skip.
  247.                CMP     AL,9
  248.                JA      NEXT_NUMBER
  249.                CBW                             ;Convert to word.
  250.                XCHG    AX,BP                   ;Swap old and new number.
  251.                MOV     CX,10                   ;Shift to left by multiplying
  252.                MUL     CX                      ; last entry by ten.
  253.                ADD     BP,AX                   ;Add new number and store in BP.
  254.                JMP     SHORT NEXT_NUMBER
  255. ;-----------------------------------------------------------------------;
  256. ; Search for dummy CONFIG.END device as signature of end of buffer.     ;
  257. ; If found, replace "D" device code with "Z" unrecognized command code. ;
  258. ;-----------------------------------------------------------------------;
  259. FIND_END:      MOV     BUFFER_START,BX         ;Save start of first command.
  260. NEXT_BYTE:     MOV     SI,OFFSET CONFIG_END    ;Point to CONFIG.END.
  261.                MOV     DI,BX                   ;Point to current buffer pos.
  262.                MOV     CX,CONFIG_END_LEN       ;Is it CONFIG.END?
  263.                REPZ    CMPSB
  264.                JZ      FOUND_END               ;If yes, found end.
  265.                INC     BX                          ;Else, increment buff pos.
  266.                CMP     BX,0FFFFH - CONFIG_END_LEN  ;End of segment?
  267.                JNZ     NEXT_BYTE                   ;If no, continue.
  268.                JMP     SHORT PAUSE             ;Else, give up search.
  269.  
  270. FOUND_END:     MOV     END_FLAG,1              ;Flag that we found CONFIG.END.
  271.                MOV     BYTE PTR ES:[BX],"Z"    ;"Z" out CONFIG.END command.
  272.                DEC     BX                      ;Adjust to buffer end
  273.                MOV     BUFFER_END,BX           ; and store.
  274. ;-------------------------------------------------------------; 
  275. ; See if user pressed key requesting CONFIG.SYS modification. ;
  276. ;-------------------------------------------------------------;
  277. PAUSE:         CALL    CK_KEY                  ;Key pressed?
  278.                JNZ     ATTENTION               ;If yes, give attention.
  279.                MOV     CX,BP                   ;Else, retrieve second delay.
  280.                JCXZ    INIT_END                ;If zero, we're done.
  281.                MOV     DX,OFFSET DELAY_MSG     ;Else, display "Press key for
  282.                CALL    PRINT_STRING            ; service" message.
  283.  
  284. WAIT_A_SEC:    CALL    DELAY                   ;Delay a second.
  285. POLL_KEY:      CALL    CK_KEY                  ;Key pressed?
  286.                JNZ     ATTENTION               ;If yes, give attention.
  287.                LOOP    WAIT_A_SEC              ;Else, continue waiting until
  288.                JMP     SHORT INIT_END          ; time out.
  289. ;--------------------------------------------------------------; 
  290. ; If keystroke other than ESC was pressed and CONFIG.END dummy ;
  291. ; device found, then we're in business; otherwise exit.
  292. ;--------------------------------------------------------------;
  293. ATTENTION:     PUSH    AX                      ;Save key press.
  294.                CALL    CLEAR_KEY               ;Clear keyboard buffer.
  295.                POP     AX                      ;Retrieve key press.
  296.                CMP     AH,ESC_KEY              ;Was is Esc?
  297.                JZ      INIT_END                ;If yes, we're done.
  298.                CMP     END_FLAG,1              ;Else, did we find CONFIG.END?
  299.                JZ      CONTINUE                ;If yes, continue.
  300.                MOV     DX,OFFSET NOT_FOUND_MSG ;Else, Display CONFIG.END not
  301.                CALL    PRINT_STRING            ; found message.
  302.                CALL    GET_KEY                 ;Wait for keystroke so it can be
  303.                JMP     SHORT INIT_END          ; read and then exit.
  304.  
  305. CONTINUE:      CALL    BUSINESS                ;Do our thing.
  306.  
  307. INIT_END:      RET                             ;Exit.
  308. INITIALIZE     ENDP
  309. ;--------------------------------------------;
  310. ;  INPUT                                     ;
  311. ;    DS = CS                                 ;
  312. ;    ES = CONFIG.SYS command buffer segment. ;
  313. ;                                            ;
  314. ;    All registers destroyed.                ;
  315. ;--------------------------------------------;
  316. BUSINESS       PROC    NEAR
  317.  
  318.                CALL    CLS                     ;Clear the screen.
  319.                MOV     DX,OFFSET HEADING       ;Display heading messages.
  320.                CALL    PRINT_STRING
  321. ;----------------------------------------------------------------------------; 
  322. ; Retrieve the commands from CONFIG.SYS buffer and place them in our buffer. ;
  323. ;----------------------------------------------------------------------------;
  324.                MOV     SI,BUFFER_START         ;Point to start of commands.
  325.                MOV     DX,BUFFER_END           ;DX = end of buffer.
  326.                MOV     BX,OFFSET DATA_STORAGE  ;Point to our storage.
  327.                PUSH    CS                      ;Destination segment our data.
  328.                POP     ES
  329.                PUSH    BUFFER_SEGMENT          ;Source segment CONFIG.SYS
  330.                POP     DS                      ; command buffer.
  331.  
  332. NEXT_COMMAND:  CMP     SI,DX                   ;End of buffer?
  333.                JAE     COMMAND_END             ;If yes, done here.
  334.                LODSB                           ;Get a byte.
  335.                CMP     AL,CR                   ;Carriage return or linefeed?
  336.                JZ      NEXT_COMMAND            ;If yes, delimiter; skip.
  337.                CMP     AL,LF
  338.                JZ      NEXT_COMMAND
  339.                PUSH    AX                      ;Else, command code character.
  340.                DEC     SI                      ;Adjust pointer.
  341.                MOV     ES:ADDRESS[BX],SI       ;Save starting address.
  342.                MOV     DI,BX                   ;Point to our storage.
  343.                CALL    RETRIEVE                ;Go retrieve the command string.
  344.                POP     AX                      ;Retrieve command code.
  345.                CMP     AL,"Z"                  ;Was it unrecognized "Z" ?
  346.                JZ      NEXT_COMMAND            ;If yes, skip.
  347.                DEC     CX                      ;Else, adjust string length less
  348.                DEC     CX                      ; code and ending linefeed.
  349.                JCXZ    NEXT_COMMAND            ;Null string?  If yes, skip.
  350.                MOV     ES:STRING_LENGTH[BX],CX ;Else, store length.
  351.                ADD     BX,TYPE DATA_RECORD     ;Point to next storage record.
  352.                JMP     SHORT NEXT_COMMAND      ;Get next command.
  353.  
  354. COMMAND_END:   PUSH    CS                      ;Back to our data segment.
  355.                POP     DS
  356.                MOV     COMMAND[BX],LAST_RECORD ; -1 as end of data signature.
  357.                CMP     BX,OFFSET DATA_STORAGE  ;Were there any commands?
  358.                JZ      BUSINESS_END            ;If no, done here.
  359. ;--------------------------------------------------;
  360. ; Display the commands and let the user edit them. ;
  361. ;--------------------------------------------------;
  362.                CALL    DISPLAY
  363.                CALL    EDIT
  364.                JC      BUSINESS_END            ;If carry, Esc was pressed.
  365. ;----------------------------------------------------------;
  366. ; Place the edited commands back in the CONFIG.SYS buffer. ;
  367. ;----------------------------------------------------------;
  368.                MOV     BX,OFFSET DATA_STORAGE  ;Point to CONFIG.SYS buffer
  369.                PUSH    BUFFER_SEGMENT          ; as destination.
  370.                POP     ES
  371.  
  372. STORE_COMMAND: CMP     COMMAND[BX],LAST_RECORD ;Is it the last record?
  373.                JZ      BUSINESS_END            ;If yes, we're all done.
  374.                TEST    COMMAND[BX],HIGH_BIT    ;Is command inactive?
  375.                JZ      REPLACE_DATA            ;If no, OK.
  376.                MOV     COMMAND[BX],"Z"         ;Else, replace with "Z".
  377. REPLACE_DATA:  MOV     SI,BX                   ;Point to command string.
  378.                MOV     DI,ADDRESS[BX]          ;Point to destination address.
  379.                CALL    REPLACE                 ;Replace the string in buffer.
  380.                ADD     BX,TYPE DATA_RECORD     ;Point to next record.
  381.                JMP     SHORT STORE_COMMAND     ;And store it.
  382.  
  383. BUSINESS_END:  CALL    CLS                     ;Exit with clean slate.
  384.                RET
  385. BUSINESS       ENDP
  386. ;---------------------------------------;
  387. ; INPUT                                 ;
  388. ;   DS:SI points to CONFIG.SYS buffer.  ;
  389. ;   ES:DI points to our storage.        ;
  390. ;                                       ;
  391. ; OUTPUT                                ;
  392. ;   SI and DI at end of string.         ;
  393. ;   CX = string length include one byte ;
  394. ;   for command code and one byte for   ;
  395. ;   CR or LF.  ASCIIZ is stripped.      ;
  396. ;                                       ;
  397. ;   AX  destroyed.                      ;
  398. ;---------------------------------------;
  399. RETRIEVE       PROC    NEAR
  400.  
  401.                XOR     CX,CX                   ;Zero in string length counter.
  402. NEXT_RETRIEVE: LODSB                           ;Get a byte.
  403.                OR      AL,AL                   ;If it's ASCIIZ zero,
  404.                JZ      NEXT_RETRIEVE           ; skip it.
  405.                STOSB                           ;Else, store it.
  406.                INC     CX                      ;Increment count.
  407.                CMP     AL,CR                   ;If terminating carriage return
  408.                JZ      RETRIEVE_END            ; or linefeed, we're done.
  409.                CMP     AL,LF
  410.                JNZ     NEXT_RETRIEVE
  411. RETRIEVE_END:  RET
  412.  
  413. RETRIEVE       ENDP
  414. ;--------------------------------------;
  415. ; INPUT                                ;
  416. ;   DS:SI points to our storage.       ;
  417. ;   ES:DI points to CONFIG.SYS buffer. ;
  418. ;   BX = current record.               ;
  419. ;                                      ;
  420. ; OUTPUT                               ;
  421. ;   ASCIIZ is reinserted in string.    ;
  422. ;   SI and DI at end of string.        ;
  423. ;                                      ;
  424. ;   AX, CX, DX, BP destroyed.          ;
  425. ;--------------------------------------;
  426. REPLACE        PROC    NEAR
  427.  
  428.                MOV     CX,STRING_LENGTH[BX]    ;Retrieve string length.
  429.                INC     CX                      ;Include command code byte.
  430.                MOV     BP,-1                   ;ASCIIZ flag.
  431.                XOR     DX,DX                   ;Leading space flag.
  432. NEXT_REPLACE:  LODSB                           ;Get a byte.
  433.                CMP     AL,"a"                  ;Capitalize.
  434.                JB      CK_LEADING
  435.                CMP     AL,"z"
  436.                JA      CK_LEADING
  437.                AND     AL,5FH
  438.  
  439. CK_LEADING:    CMP     AL,SPACE                ;Is it a leading space?
  440.                JNZ     CK_ADD_ZERO             ;If no, check if zero time.
  441.                CMP     DX,1                    ;If command only thing stored
  442.                JZ      NEXT_REPLACE            ; so far, then it's leading.
  443.  
  444. CK_ADD_ZERO:   CMP     BP,-1                   ;Have we stored a zero yet?
  445.                JNZ     CK_CR_LF                ;If yes, check CR and LF.
  446.                CMP     AL,SPACE                ;Else, if it's delimiting
  447.                JZ      ASCIIZ                  ; space, comma, slash, CR or LF
  448.                CMP     AL,COMMA                ; then store a terminating
  449.                JZ      ASCIIZ                  ; right in front of it.
  450.                CMP     AL,FORWARD_SLASH
  451.                JZ      ASCIIZ
  452.                CMP     AL,CR
  453.                JZ      ASCIIZ
  454.                CMP     AL,LF
  455.                JNZ     STORE_BYTE
  456.  
  457. ASCIIZ:        XCHG    AX,BP                   ;Swap special character.
  458.                XOR     AX,AX                   ;Store the zero.
  459.                STOSB                           ;Retrieve the character and
  460.                XCHG    AX,BP                   ; zero in BP as flag.
  461.  
  462. CK_CR_LF:      CMP     AL,CR                   ;If CR or LF we're done here.
  463.                JZ      PAD_SPACES
  464.                CMP     AL,LF
  465.                JZ      PAD_SPACES
  466.  
  467. STORE_BYTE:    STOSB                           ;Store the byte.
  468.                INC     DX                      ;Increment count.
  469.                LOOP    NEXT_REPLACE
  470.  
  471. PAD_SPACES:    JCXZ    REPLACE_END             ;If end of string, done.
  472.                MOV     AL,SPACE                ;Else, move leading spaces
  473.                REP     STOSB                   ; to end of string.
  474. REPLACE_END:   RET
  475. REPLACE        ENDP
  476. ;------------------------------------------;
  477. ;   Display the commands on the screen.    ;
  478. ;   All registers destroyed.               ;
  479. ;------------------------------------------;
  480. DISPLAY        PROC    NEAR
  481.  
  482.                MOV     BP,OFFSET DATA_STORAGE  ;Point to data storage.
  483.                MOV     DH,ROW_START            ;Point to first display row.
  484.  
  485. NEXT_DISPLAY:  XOR     DL,DL                   ;Column zero.
  486.                CALL    SET_CURSOR              ;Set cursor position.
  487.                CMP     COMMAND[BP],LAST_RECORD ;Is it the last record?
  488.                JZ      DISPLAY_END             ;If yes, done here.
  489.                CALL    DECODE                  ;Else, decode the command.
  490.                MOV     AL,"="                  ;Add quotes and a space.
  491.                CALL    WRITE_TTY
  492.                MOV     AL,SPACE
  493.                CALL    WRITE_TTY
  494.                MOV     SI,BP                   ;Point to command string.
  495.                INC     SI
  496.                MOV     CX,STRING_LENGTH[BP]    ;Retrieve the string length.
  497. NEXT_ARGUMENT: LODSB                           ;Display the command.
  498.                CALL    WRITE_TTY
  499.                LOOP    NEXT_ARGUMENT
  500.                ADD     BP,TYPE DATA_RECORD     ;Point to next record.
  501.                INC     DH                      ;Next cursor row.
  502.                CMP     DH,25                   ;Is it row 25?
  503.                JNZ     NEXT_DISPLAY            ;If no, continue.
  504.  
  505. DISPLAY_END:   RET
  506. DISPLAY        ENDP
  507. ;-----------------------------------------;
  508. ; INPUT                                   ;
  509. ;   BP points to command.                 ;
  510. ;                                         ;
  511. ; OUTPUT                                  ;
  512. ;   The command is decoded and displayed. ;
  513. ;                                         ;
  514. ;   AX, CX, SI and DI destroyed.          ;
  515. ;-----------------------------------------;
  516. DECODE         PROC    NEAR
  517.  
  518.                MOV     SI,OFFSET INACTIVE      ;Assume command inactive.
  519.                MOV     AL,COMMAND[BP]          ;Retrieve command.
  520.                TEST    AL,HIGH_BIT             ;Is it marked inactive?
  521.                JNZ     FOUND_COMMAND           ;If yes, assumed right.
  522.                MOV     DI,OFFSET CODES         ;Else, point to codes.
  523.                MOV     CX,CODES_LENGTH         ;Number of codes.
  524.                REPNZ   SCASB                   ;Search for match.
  525.                MOV     SI,OFFSET TABLE_END     ;Point to interpolation table.
  526.                INC     CX                      ;Adjust count.
  527. FIND_COMMAND:  SUB     SI,COMMAND_SIZE         ;Point to appropriate command.
  528.                LOOP    FIND_COMMAND
  529.  
  530. FOUND_COMMAND: MOV     CX,COMMAND_SIZE         ;Command string length.
  531. DISPLAY_CMD:   LODSB                           ;Display it.
  532.                CALL    WRITE_TTY
  533.                LOOP    DISPLAY_CMD
  534.                RET
  535.  
  536. DECODE         ENDP
  537. ;----------------------------------;
  538. ;  OUTPUT                          ;
  539. ;    Carry flag = 0 if good edit.  ;
  540. ;    Carry flag = 1 if edit abort. ;
  541. ;                                  ;
  542. ;    All registers destroyed.      ;
  543. ;----------------------------------;
  544. EDIT           PROC    NEAR
  545.  
  546.                MOV     BP,OFFSET DATA_STORAGE  ;Point to data storage.
  547.                MOV     DH,ROW_START            ;Point to first row.
  548.                MOV     BL,INVERSE              ;Highlight the first command.
  549.                CALL    HIGHLIGHT_BAR           ;Return with DI = 1; first char.
  550.  
  551. NEXT_KEY:      CALL    GET_KEY                 ;Get a keystroke.
  552.                CMP     AH,ESC_KEY              ;Is it ESC?
  553.                JZ      NO_CHANGE               ;If yes, exit with no change.
  554.                CMP     AH,F2_KEY               ;Is it F2?
  555.                JZ      EDIT_END                ;If yes, exit with changes.
  556.                CMP     AL,BS                   ;Is it backspace?
  557.                JZ      FUNCTION                ;If yes, function.
  558.                CMP     AL,CR                   ;Is it carriage return?
  559.                JZ      FUNCTION                ;If yes, function.
  560.                CMP     AH,F1_KEY               ;Is it F1 or above?
  561.                JAE     FUNCTION                ;If yes, function.
  562.  
  563. ASCII:         CMP     AL,SPACE                ;Is it space or above?
  564.                JB      NEXT_KEY                ;If no, skip.
  565.                CMP     DI,STRING_LENGTH[BP]    ;Else, are we at end of field?
  566.                JA      NEXT_KEY                ;If yes, skip.
  567.                MOV     COMMAND[BP+DI],AL       ;Else, store character.
  568.                INC     DI                      ;Point to next storage.
  569.                INC     DL                      ;Increment cursor column.
  570.                CALL    WRITE_TTY               ;Write the character to screen.
  571.                JMP     SHORT NEXT_KEY          ;Get next keystroke.
  572.  
  573. FUNCTION:      MOV     AL,AH                   ;Scan code in AL.
  574.                MOV     CX,KEY_COUNT            ;Count of active functions.
  575.                PUSH    DI                      ;Preserve DI.
  576.                MOV     DI,OFFSET DISPATCH_KEY  ;Point to active keys.
  577.                REPNZ   SCASB                   ;Scan for match.
  578.                POP     DI                      ;Retrieve DI.
  579.                JNZ     NEXT_KEY                ;If no match, next key.
  580.                MOV     SI,OFFSET DISPATCH_END  ;Else, point to dispatch table.
  581.                SHL     CX,1                    ;Convert to word offset.
  582.                SUB     SI,CX                   ;Point to appropriate procedure
  583.                CALL    DS:[SI]                 ; and go do it.
  584.                JMP     SHORT NEXT_KEY          ;Get next keystroke.
  585.  
  586. NO_CHANGE:     STC
  587. EDIT_END:      RET
  588.  
  589. EDIT           ENDP
  590. ;----------------------------------------------------------------------------; 
  591. ; The following are the active function, arrow and backspace key procedures. ;
  592. ;----------------------------------------------------------------------------;
  593. F1             PROC    NEAR
  594.  
  595.                PUSH    DI                      ;Preserve DI and DX.
  596.                PUSH    DX
  597.                XOR     DL,DL                   ;Column zero.
  598.                CALL    SET_CURSOR              ;Set cursor.
  599.                XOR     COMMAND[BP],HIGH_BIT    ;Toggle active state.
  600.                CALL    DECODE                  ;Decode the command.
  601.                POP     DX                      ;Restore cursor position.
  602.                CALL    SET_CURSOR
  603.                POP     DI                      ;Restore DI.
  604.                RET
  605.  
  606. F1             ENDP
  607. ;------------------------------;
  608. BACKSPACE      PROC    NEAR
  609.  
  610.                CMP     DI,1                    ;Are we already at first char?
  611.                JZ      BACKSPACE_END           ;If yes, skip.
  612.                DEC     DL                      ;Else, decrement cursor
  613.                DEC     DI                      ; and character storage position.
  614.                MOV     COMMAND[BP+DI],SPACE    ;Store a space.
  615.                MOV     AL,BS                   ;Write a backspace, space and
  616.                CALL    WRITE_TTY               ;backspace to screen.
  617.                MOV     AL,SPACE
  618.                CALL    WRITE_TTY
  619.                MOV     AL,BS
  620.                CALL    WRITE_TTY
  621. BACKSPACE_END: RET
  622.  
  623. BACKSPACE      ENDP
  624. ;------------------------------;
  625. UP_ARROW       PROC    NEAR
  626.  
  627.                CMP     BP,OFFSET DATA_STORAGE  ;Are we already at top row?
  628.                JZ      UP_ARROW_END            ;If yes, skip.
  629.                MOV     BL,NORMAL               ;Else, return to normal
  630.                CALL    HIGHLIGHT_BAR           ; attribute current row.
  631.                SUB     BP,TYPE DATA_RECORD     ;Move up a record.
  632.                DEC     DH                      ;Move cursor up one.
  633.                MOV     BL,INVERSE              ;Display line in inverse video.
  634.                CALL    HIGHLIGHT_BAR
  635. UP_ARROW_END:  RET
  636.  
  637. UP_ARROW       ENDP
  638. ;------------------------------;
  639. DN_ARROW       PROC    NEAR
  640.  
  641.                CMP     COMMAND[BP+TYPE DATA_RECORD],LAST_RECORD
  642.                JZ      DN_ARROW_END
  643.                CMP     DH,24                   ;If last record already or
  644.                JZ      DN_ARROW_END            ; bottom of screen, skip.
  645.                MOV     BL,NORMAL               ;Else, return current row to
  646.                CALL    HIGHLIGHT_BAR           ; normal.
  647.                ADD     BP,TYPE DATA_RECORD     ;Go down a record.
  648.                INC     DH                      ;And down a row.
  649.                MOV     BL,INVERSE              ;Display the line inverse video.
  650.                CALL    HIGHLIGHT_BAR
  651. DN_ARROW_END:  RET
  652.  
  653. DN_ARROW       ENDP
  654. ;------------------------------;
  655. LT_ARROW       PROC    NEAR
  656.  
  657.                CMP     DI,1                    ;Are we already first positon?
  658.                JZ      LT_ARROW_END            ;If yes, skip.
  659.                DEC     DI                      ;Else, decrement storage position
  660.                DEC     DL                      ; and cursor position.
  661.                CALL    SET_CURSOR
  662. LT_ARROW_END:  RET
  663.  
  664. LT_ARROW       ENDP
  665. ;------------------------------;
  666. RT_ARROW       PROC    NEAR
  667.  
  668.                CMP     DI,STRING_LENGTH[BP]    ;Are we already end of string?
  669.                JA      RT_ARROW_END            ;If yes, skip.
  670.                INC     DI                      ;Else, increment storage position
  671.                INC     DL                      ; and cursor position.
  672.                CALL    SET_CURSOR
  673. RT_ARROW_END:  RET
  674.  
  675. RT_ARROW       ENDP
  676. ;------------------------------;
  677. HOME           PROC    NEAR
  678.  
  679.                MOV     DI,1                    ;Home storage position
  680.                MOV     DL,COL_START            ; and cursor.
  681.                CALL    SET_CURSOR
  682.                RET
  683.  
  684. HOME           ENDP
  685. ;------------------------------;
  686. END_CURSOR     PROC    NEAR
  687.  
  688.                MOV     DI,STRING_LENGTH[BP]    ;Retrieve string length.
  689.                MOV     CX,DI
  690.                MOV     DL,CL
  691.                ADD     DL,COL_START            ;Add to starting column.
  692.                INC     DI                      ;Adjust.
  693.                CALL    SET_CURSOR              ;Set cursor.
  694.                RET
  695.  
  696. END_CURSOR     ENDP
  697. ;------------------------------;
  698. PG_DN          PROC    NEAR
  699.  
  700.                MOV     BL,NORMAL               ;Current postion back to normal.
  701.                CALL    HIGHLIGHT_BAR
  702. NEXT_PG_DN:    CMP     COMMAND[BP+TYPE DATA_RECORD],LAST_RECORD
  703.                JZ      PAGE_END
  704.                ADD     BP,TYPE DATA_RECORD     ;If not already last position,
  705.                INC     DH                      ; go to it.
  706.                JMP     SHORT NEXT_PG_DN
  707. PAGE_END:      MOV     BL,INVERSE              ;And display it in inverse video.
  708.                CALL    HIGHLIGHT_BAR
  709.                RET
  710.  
  711. PG_DN          ENDP
  712. ;------------------------------;
  713. PG_UP          PROC    NEAR
  714.  
  715.                MOV     BL,NORMAL               ;Restore current position to
  716.                CALL    HIGHLIGHT_BAR           ; normal.
  717.                MOV     BP,OFFSET DATA_STORAGE  ;Move to top command.
  718.                MOV     DH,ROW_START            ;And cursor position.
  719.                MOV     BL,INVERSE              ;And highlight.
  720.                CALL    HIGHLIGHT_BAR
  721.                RET
  722.  
  723. PG_UP          ENDP
  724. ;------------------------------------------;
  725. ; INPUT                                    ;
  726. ;   BL = attribute.                        ;
  727. ;   BP points to current command.          ;
  728. ;                                          ;
  729. ; OUTPUT                                   ;
  730. ;   DI = 1 (First storage position.)       ;
  731. ;   DL = cursor column start.              ;
  732. ;                                          ;
  733. ;   CX, SI destroyed.                      ;
  734. ;------------------------------------------;
  735. HIGHLIGHT_BAR  PROC    NEAR
  736.  
  737.                MOV     CX,STRING_LENGTH[BP]    ;Retrieve string length.
  738.                MOV     SI,BP                   ;Point to command.
  739.                INC     SI                      ;Adjust.
  740.                MOV     DL,COL_START            ;Point to first position.
  741. HIGHLIGHT:     CALL    SET_CURSOR              ;Set the cursor.
  742.                LODSB
  743.                PUSH    CX                      ;Preserve CX.
  744.                MOV     CX,1
  745.                MOV     AH,9                    ;Write char/attribute.
  746.                INT     10H
  747.                INC     DL                      ;Increment cursor postion.
  748.                POP     CX
  749.                LOOP    HIGHLIGHT
  750.                MOV     DL,COL_START            ;Point to first position again.
  751.                CALL    SET_CURSOR              ;Set cursor.
  752.                MOV     DI,1                    ;Return with DI = first storage.
  753.                RET
  754.  
  755. HIGHLIGHT_BAR  ENDP
  756. ;---------------------------------------; 
  757. ; The following are support procedures. ;
  758. ;---------------------------------------;
  759. WRITE_TTY      PROC    NEAR
  760.  
  761.                MOV     AH,0EH                  ;Write TTY via BIOS.
  762.                INT     10H
  763.                RET
  764.  
  765. WRITE_TTY      ENDP
  766. ;------------------------------;
  767. SET_CURSOR     PROC    NEAR
  768.  
  769.                XOR     BH,BH                   ;Enter with DX = cursor postion.
  770.                MOV     AH,2                    ;Set cursor position via BIOS.
  771.                INT     10H
  772.                RET
  773.  
  774. SET_CURSOR     ENDP
  775. ;------------------------------;
  776. CLS            PROC    NEAR
  777.  
  778.                MOV     AH,0FH                  ;Get current video mode.
  779.                INT     10H
  780.                XOR     AH,AH                   ;Set current video mode.
  781.                INT     10H                     ;Result is a clear screen.
  782.                RET
  783.  
  784. CLS            ENDP
  785. ;------------------------------;
  786. DELAY          PROC    NEAR
  787.  
  788.                PUSH    DS                      ;Preserve data segment.
  789.                MOV     AX,40H                  ;Point to BIOS data segment.
  790.                MOV     DS,AX
  791.                MOV     AX,DS:[6CH]             ;Retrieve timer low.
  792.                ADD     AX,18                   ;Add 18 counts per second.
  793. NEXT_COUNT:    MOV     DX,DS:[6CH]             ;Retrieve timer low.
  794.                CMP     DX,AX                   ;Have we timed out?
  795.                JNZ     NEXT_COUNT              ;If not, wait until second up.
  796.                POP     DS                      ;Restore data segment.
  797.                RET
  798.  
  799. DELAY          ENDP
  800. ;------------------------------;
  801. GET_KEY:       MOV     AH,0                    ;Retrieve keystroke via BIOS.
  802.                INT     16H
  803.                RET
  804.  
  805. CK_KEY:        MOV     AH,1                    ;Check for keystroke via BIOS.
  806.                INT     16H
  807.                RET
  808.  
  809. CLEAR_IT:      CALL    GET_KEY
  810. CLEAR_KEY:     CALL    CK_KEY                  ;Clear keyboard buffer.
  811.                JNZ     CLEAR_IT
  812.                RET
  813. ;------------------------------;
  814. PRINT_STRING:  MOV     AH,9                    ;Print string via DOS.
  815.                INT     21H
  816.                RET
  817. ;------------------------------;
  818. DATA_STORAGE   EQU     $
  819.  
  820. _TEXT          ENDS
  821.                END
  822.